package org.wheel.plugins.toolkit.jdbc.pool.util;

import cn.hutool.core.util.PageUtil;
import org.wheel.module.core.util.Page;
import org.wheel.plugins.toolkit.jdbc.pool.bean.DatabaseConnection;
import org.wheel.plugins.toolkit.jdbc.pool.util.excution.*;
import org.wheel.plugins.toolkit.sql.core.LambdaDeleteWrapper;
import org.wheel.plugins.toolkit.sql.core.LambdaInsertWrapper;
import org.wheel.plugins.toolkit.sql.core.LambdaQueryWrapper;
import org.wheel.plugins.toolkit.sql.core.LambdaUpdateWrapper;
import org.wheel.plugins.toolkit.sql.enums.SqlModel;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public final class LambdaSqlExecutionUtil {

    private static final SqlQueryExecutor queryExecutor = new SqlQueryExecutor();
    private static final SqlPageExecutor pageExecutor  = new SqlPageExecutor();
    private static final SqlUpdateExecutor updateExecutor= new SqlUpdateExecutor();


    /** ---------- 内部分页查询，返回所有结果。 注意，尽量不要查询大数据量数据 ---------- **/
    public static <T, J> List<J> listAll(DatabaseConnection conn,
                                   LambdaQueryWrapper<T> wrapper,
                                   Class<J> beanClass) {
        int pageSize = 1000;
        long count = count(conn, wrapper);
        if(count <= pageSize){
            return list(conn, wrapper, beanClass);
        }else{
            int totalPages = PageUtil.totalPage(count, pageSize);
            SqlTuple<String, LinkedHashMap<String,Object>, SqlModel> t =
                    LambdaSqlResolver.resolve(wrapper);
            return IntStream.rangeClosed(1, totalPages).boxed()
                    .flatMap(pageNo-> {
                        String finalSql = pageExecutor.rebuildPageSql(t.getSql(), pageNo, pageSize);
                        return queryExecutor.queryForList(conn, finalSql, t.getParams(), t.getSqlModel(), beanClass).stream();
                    }).collect(Collectors.toList());
        }
    }

    /* ---------- 查询 ---------- */
    public static <T, J> List<J> list(DatabaseConnection conn,
                                   LambdaQueryWrapper<T> wrapper,
                                   Class<J> beanClass) {
        SqlTuple<String, LinkedHashMap<String,Object>, SqlModel> t =
                LambdaSqlResolver.resolve(wrapper);
        return queryExecutor.queryForList(conn, t.getSql(), t.getParams(), t.getSqlModel(), beanClass);
    }

    public static <T, J> J one(DatabaseConnection conn,
                            LambdaQueryWrapper<T> wrapper,
                            Class<J> beanClass) {
        SqlTuple<String, LinkedHashMap<String,Object>, SqlModel> t =
                LambdaSqlResolver.resolve(wrapper);
        return queryExecutor.queryForObject(conn, t.getSql(), t.getParams(), t.getSqlModel(), beanClass);
    }

    public static <T> long count(DatabaseConnection conn, LambdaQueryWrapper<T> wrapper){
        return queryExecutor.executeCountSqlQuery(conn, wrapper.getCountSql(), wrapper.getParamMap(), wrapper.getSqlModel());
    }

    /* ---------- 分页 ---------- */
    public static <T, J> Page<J> page(DatabaseConnection conn,
                                   LambdaQueryWrapper<T> wrapper,
                                   long pageNo,
                                   long pageSize,
                                   Class<J> beanClass) {
//        SqlTuple<String, LinkedHashMap<String,Object>, SqlModel> t =
//                LambdaSqlResolver.resolve(wrapper);
        // 手工拼 #page{}/{}# 片段
//        String pageSql = SQLHelper.resetSqlPageInfo(t.getSql(), pageNo, pageSize);
//        return pageExecutor.queryPage(conn, pageSql, t.getParams(), pageNo, pageSize, t.getSqlModel(), beanClass);

        wrapper.page(Long.valueOf(pageNo).intValue(), Long.valueOf(pageSize).intValue());
        String countSql = wrapper.getCountSql();
        String pageSql = wrapper.getSql();

        return pageExecutor.queryPage(conn, countSql, pageSql, wrapper.getParamMap(),
                pageNo, pageSize, wrapper.getSqlModel(), beanClass);

    }

    /* ---------- 更新 ---------- */
    public static <T> int update(DatabaseConnection conn,
                                 LambdaUpdateWrapper<T> wrapper) {
        SqlTuple<String, LinkedHashMap<String,Object>, SqlModel> t =
                LambdaSqlResolver.resolve(wrapper); // 同理实现
        return updateExecutor.update(conn, t.getSql(), t.getParams(), t.getSqlModel());
    }
    public static <T> int[] updateBatch(DatabaseConnection conn,
                                 Collection<LambdaUpdateWrapper<T>> wrappers) {
        return updateExecutor.batchUpdate(conn, wrappers.stream().map(LambdaSqlResolver::resolve).toList());
    }
    /* ---------- 删除 ---------- */
    public static <T> int delete(DatabaseConnection conn,
                                 LambdaDeleteWrapper<T> wrapper) {
        SqlTuple<String, LinkedHashMap<String,Object>, SqlModel> t =
                LambdaSqlResolver.resolve(wrapper); // 同理实现
        return updateExecutor.update(conn, t.getSql(), t.getParams(), t.getSqlModel());
    }
    /** ---------- 批量删除 ---------- */
    public static <T> int[] deleteBatch(DatabaseConnection conn, Collection<LambdaDeleteWrapper<T>> wrappers){
        return updateExecutor.batchUpdate(conn, wrappers.stream().map(LambdaSqlResolver::resolve).toList());
    }

    /* ---------- 新增方法 ---------- */
    /** ---------- 插入 ---------- */
    public static <T> int save(DatabaseConnection conn,
                               LambdaInsertWrapper<T> wrapper) {
        SqlTuple<String, LinkedHashMap<String,Object>, SqlModel> t =
                LambdaSqlResolver.resolve(wrapper); // 注意：LambdaSqlResolver 需支持 LambdaInsertWrapper
        return updateExecutor.update(conn, t.getSql(), t.getParams(), t.getSqlModel());
    }

    /** ---------- 批量插入 ---------- */
    public static <T> int[] saveBatch(DatabaseConnection conn, Collection<LambdaInsertWrapper<T>> wrappers){
        return updateExecutor.batchUpdate(conn, wrappers.stream().map(LambdaSqlResolver::resolve).toList());
    }

    /** ---------- 插入并返回主键 ---------- */
    public static <T> T saveAndGetId(DatabaseConnection conn,
                                     LambdaInsertWrapper<T> wrapper) {
        SqlTuple<String, LinkedHashMap<String,Object>, SqlModel> t =
                LambdaSqlResolver.resolve(wrapper);

        String sql = t.getSql();
        SqlModel model = t.getSqlModel();
        // 调用更新执行器的插入方法并获取主键
        return updateExecutor.insertWithGeneratedKeys(conn, sql, wrapper.getFullParamMap(), model);
    }
}
